﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using NetClientFramework.Helper;
using NetClientFramework.ViewModel;

namespace Demo.Snake.Application.ViewModel
{
    public class ShellViewModel : ViewModelBase
    {
        private bool canPlay; //是否可以操作游戏
        private ObservableCollection<Infrastructure.Core.Snake> collectionSnake;//蛇集合
        private readonly int defaultSize = 5; //默认蛇长度
        private bool foodEat = true; //食物是否被吃
        private DispatcherTimer foodTimer; //食物线程
        private bool isCreate; //食物是否已经创建成功
        private readonly Random location = new Random(); //食物位置
        private List<int> orientation; //操作方向及转折点,1:left,2:right,3:up,4:doown;row;column,以及某个方向包含蛇体的索引  
        private int orientationIndex; //需要执行的某个方向的索引
        private readonly List<List<int>> orientationList = new List<List<int>>(); //记录所有操作
        private string playState; //状态
        private double playtime; //时间
        private int row, col; //食物的行与列
        private int score; //分数
        private bool showGridLines;//是否显示网格线
        private bool snakeEat; //蛇是否吃到食物
        private int snakeHead; //蛇的头部
        private readonly List<int> snakeIndex = new List<int>(); //记录所有蛇的索引
        private DispatcherTimer snakeTimer; //游戏线程
        private double speed;//速度
        private string stopContent;//停止按钮显示内容
        private bool stopIsEnabled;//停止按钮可操作性
        private string time;//时间

        /// <summary>
        ///     蛇集合
        /// </summary>
        public ObservableCollection<Infrastructure.Core.Snake> CollectionSnake
        {
            get => collectionSnake ?? (collectionSnake = new ObservableCollection<Infrastructure.Core.Snake>());
            set
            {
                collectionSnake = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        ///     暂停按钮状态
        /// </summary>
        public bool StopIsEnabled
        {
            get => stopIsEnabled;
            set
            {
                stopIsEnabled = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        ///     暂停按钮的内容
        /// </summary>
        public string StopContent
        {
            get => stopContent;
            set
            {
                stopContent = value;
                RaisePropertyChanged();
            }
        }

        public string PlayState
        {
            get => playState;
            set
            {
                playState = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        ///     移动的速度
        /// </summary>
        public double Speed
        {
            get => speed;
            set
            {
                speed = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        ///     游戏时间
        /// </summary>
        public string Time
        {
            get => time;
            set
            {
                time = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        ///     游戏分数
        /// </summary>
        public int Score
        {
            get => score;
            set
            {
                score = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        ///     是否显示网格线
        /// </summary>
        public bool ShowGridLines
        {
            get => showGridLines;
            set
            {
                showGridLines = value;
                RaisePropertyChanged();
            }
        }


        /// <summary>
        ///     键盘事件
        /// </summary>
        public ICommand KeyCommand { get; set; }


        /// <summary>
        ///     激活主窗体被取消
        /// </summary>
        public ICommand DeactivatedCommand { get; set; }


        /// <summary>
        ///     开始
        /// </summary>
        public ICommand StartCommand { get; set; }


        /// <summary>
        ///     停止
        /// </summary>
        public ICommand StopCommand { get; set; }

        /// <summary>
        ///     初始化事件
        /// </summary>
        public override void OnInitCommand()
        {
            base.OnInitCommand();
            KeyCommand = new DelegateCommand(OnKeyCommand);
            DeactivatedCommand = new DelegateCommand(OnDeactivatedCommand);
            StartCommand = new DelegateCommand(OnStartCommand);
            StopCommand = new DelegateCommand(OnStopCommand);
        }

        private void OnStopCommand(object ob)
        {
            Stop();
        }

        private void OnStartCommand(object ob)
        {
            Start();
        }


        /// <summary>
        ///     激活主窗体被取消
        /// </summary>
        /// <param name="obj"></param>
        private void OnDeactivatedCommand(object obj)
        {
            if (snakeTimer.IsEnabled) Stop();
        }


        /// <summary>
        ///     键盘事件
        /// </summary>
        /// <param name="obj"></param>
        private void OnKeyCommand(object obj)
        {
            try
            {
                string key = obj as string;
                if (key == "Right") GameKeyDown(Key.Right);
                if (key == "D")
                    GameKeyDown(Key.D);
                else if (key == "Left")
                    GameKeyDown(Key.Left);
                else if (key == "A")
                    GameKeyDown(Key.A);
                else if (key == "Up")
                    GameKeyDown(Key.Up);
                else if (key == "W")
                    GameKeyDown(Key.W);
                else if (key == "Down")
                    GameKeyDown(Key.Down);
                else if (key == "S")
                    GameKeyDown(Key.S);
                //start
                else if (key == "Z")
                    GameKeyDown(Key.Z);
                //stop
                else if (key == "X")
                    GameKeyDown(Key.X);
                //加速
                else if (key == "R")
                    GameKeyDown(Key.R);
                //减速
                else if (key == "E")
                    GameKeyDown(Key.E);
                //显示网格
                else if (key == "Q") GameKeyDown(Key.Q);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                LogHelper.Error(e.Message, e);
            }
        }


        /// <summary>
        ///     初始化游戏环境
        /// </summary>
        /// <param name="ob"></param>
        public override void OnLoadedCommand(object ob)
        {
            base.OnLoadedCommand(ob);
            Speed = 400;
            //加载游戏线程
            snakeTimer = new DispatcherTimer
            {
                Interval = TimeSpan.FromMilliseconds(600 - Speed)
            };
            snakeTimer.Tick += SnakeTimer_Tick;
            StopIsEnabled = false;
            snakeTimer.IsEnabled = false;
            PlayState = "未开始";
            StopContent = "暂停";
            //食物线程
            foodTimer = new DispatcherTimer
            {
                Interval = snakeTimer.Interval
            };
            foodTimer.Tick += FoodTimer_Tick;
        }

        #region 开始游戏

        public void Start()
        {
            snakeTimer.IsEnabled = false;
            snakeIndex.Clear();
            //初始化方向
            orientationList.Clear();
            orientation = new List<int>
            {
                2, //方向
                0, //转折行
                0 //转折列
            };
            //清除所有点
            CollectionSnake.Clear();
            // 初始化蛇
            for (int i = 0; i < defaultSize; i++)
            {
                Infrastructure.Core.Snake snake = new Infrastructure.Core.Snake();
                snake.Column = i;
                CollectionSnake.Add(snake);
                snakeIndex.Add(CollectionSnake.IndexOf(snake));
                orientation.Add(i);
            }

            orientationList.Add(orientation);
            canPlay = true;
            Score = 0;
            playtime = 0;
            foodEat = true;
            foodTimer.Start();
            StopIsEnabled = true;
            snakeTimer.IsEnabled = true;
            PlayState = "进行中";
            snakeTimer.Start();
            //sp.PlayLooping();
        }

        #endregion

        #region 暂停游戏

        public void Stop()
        {
            if (StopContent == "暂停")
            {
                snakeTimer.Stop();
                canPlay = false;
                StopContent = "继续";
                PlayState = "暂停中";
                foodTimer.Stop();
                //sp.Stop();
            }
            else
            {
                StopContent = "暂停";
                snakeTimer.Start();
                PlayState = "进行中";
                foodTimer.Start();
                //sp.PlayLooping();
            }
        }

        #endregion

        #region 游戏运行中

        public void SnakeTimer_Tick(object sender, EventArgs e)
        {
            if (IsGameOver())
            {
                PlayState = "已结束";
                foodTimer.Stop();
                snakeTimer.IsEnabled = false;
                canPlay = false;
                StopIsEnabled = false;
                //sp.Stop();
                MessageBox.Show("你玩完啦！", "贪吃蛇", MessageBoxButton.OK);
                return;
            }

            if (snakeEat)
            {
                snakeEat = false;
                return;
            }

            //更新分数与时间
            playtime += snakeTimer.Interval.TotalMilliseconds / 1000;
            Time = playtime.ToString("#0.000");
            //更新速度
            snakeTimer.Interval = TimeSpan.FromMilliseconds(600 - Speed);
            //检测食物是否被吃掉
            orientationIndex = orientationList.Count - 1;
            //计算左
            if (orientationList[orientationIndex][0] == 1)
            {
                if (CollectionSnake[snakeIndex[snakeHead]].Row == row
                    && CollectionSnake[snakeIndex[snakeHead]].Column - 1 == col)
                    foodEat = true;
            }
            //计算右
            else if (orientationList[orientationIndex][0] == 2)
            {
                if (CollectionSnake[snakeIndex[snakeHead]].Row == row
                    && CollectionSnake[snakeIndex[snakeHead]].Column + 1 == col)
                    foodEat = true;
            }
            //计算上
            else if (orientationList[orientationIndex][0] == 3)
            {
                if (CollectionSnake[snakeIndex[snakeHead]].Row - 1 == row
                    && CollectionSnake[snakeIndex[snakeHead]].Column == col)
                    foodEat = true;
            }
            //计算下
            else if (orientationList[orientationIndex][0] == 4)
            {
                if (CollectionSnake[snakeIndex[snakeHead]].Row + 1 == row
                    && CollectionSnake[snakeIndex[snakeHead]].Column == col)
                    foodEat = true;
            }

            if (foodEat)
            {
                Score += 10;
                snakeEat = true;
                snakeHead++;
                snakeIndex.Add(snakeHead);
                orientationList[orientationIndex].Add(snakeHead);
            }

            //移动蛇
            //orientationIndex = orientationList.Count - 1;
            for (int j = orientationIndex; j >= 0; j--)
            {
                for (int i = orientationList[j].Count - 1; i >= 3; i--)
                {
                    Infrastructure.Core.Snake snake = CollectionSnake[orientationList[j][i]];
                    //左
                    if (orientationList[j][0] == 1)
                        snake.Column = snake.Column - 1;
                    //右
                    else if (orientationList[j][0] == 2)
                        snake.Column = snake.Column + 1;
                    //上
                    else if (orientationList[j][0] == 3)
                        snake.Row = snake.Row - 1;
                    //下
                    else if (orientationList[j][0] == 4) snake.Row = snake.Row + 1;
                    canPlay = true;
                    //将转折点从一个方向移到另一个方向
                    if (j < orientationIndex)
                        if (snake.Row == orientationList[j + 1][1] && snake.Column == orientationList[j + 1][2])
                        {
                            orientationList[j + 1].Add(orientationList[j][i]);
                            orientationList[j].RemoveAt(i);
                        }
                }

                //删除最后一个方向，如果没有元素
                if (j == 0 && orientationList[j].Count == 3)
                {
                    orientationList.RemoveAt(j);
                    return;
                }
            }
        }

        #endregion

        #region 键盘操作

        public void GameKeyDown(Key key)
        {
            orientationIndex = orientationList.Count - 1;
            //下
            if (canPlay && (key == Key.Down || key == Key.S))
            {
                if (orientationList[orientationIndex][0] == 4 || orientationList[orientationIndex][0] == 3) return;
                AddDirection(4);
            }
            //上
            else if (canPlay && (key == Key.Up || key == Key.W))
            {
                if (orientationList[orientationIndex][0] == 4 || orientationList[orientationIndex][0] == 3) return;
                AddDirection(3);
            }
            //左
            else if (canPlay && (key == Key.Left || key == Key.A))
            {
                if (orientationList[orientationIndex][0] == 1 || orientationList[orientationIndex][0] == 2) return;
                AddDirection(1);
            }
            //右
            else if (canPlay && (key == Key.Right || key == Key.D))
            {
                if (orientationList[orientationIndex][0] == 1 || orientationList[orientationIndex][0] == 2) return;
                AddDirection(2);
            }
            //start
            else if (key == Key.Z)
            {
                Start();
            }
            //stop
            else if (StopIsEnabled && key == Key.X)
            {
                Stop();
            }
            //加速
            else if (key == Key.R)
            {
                Speed += 5;
            }
            //减速
            else if (key == Key.E)
            {
                Speed -= 5;
            }
            //显示网格
            else if (key == Key.Q)
            {
                if (ShowGridLines)
                    ShowGridLines = false;
                else
                    ShowGridLines = true;
            }
        }

        #endregion

        #region 增加方向

        public void AddDirection(int direction)
        {
            snakeHead = snakeIndex.Count - 1;
            Infrastructure.Core.Snake snake = CollectionSnake[snakeHead];
            orientation = new List<int>
            {
                direction,
                snake.Row,
                snake.Column,
                snakeHead
            };
            orientationList[orientationIndex].RemoveAt(orientationList[orientationIndex].LastIndexOf(snakeHead));
            orientationList.Add(orientation);
            //防止频繁按键
            canPlay = false;
        }

        #endregion

        #region 检测游戏是否结束

        public bool IsGameOver()
        {
            snakeHead = snakeIndex.Count - 1;
            Infrastructure.Core.Snake snake = CollectionSnake[snakeHead];
            bool over = snake.Row == 0 && orientationList[orientationList.Count - 1][0] == 3
                        || snake.Row > 49
                        || snake.Column == 0 && orientationList[orientationList.Count - 1][0] == 1
                        || snake.Column > 59;
            if (over) return true;
            for (int i = 0; i < snakeIndex.Count - 1; i++)
                for (int j = i + 1; j < snakeIndex.Count; j++)
                    if (CollectionSnake[i].Column == CollectionSnake[j].Column &&
                        CollectionSnake[i].Row == CollectionSnake[j].Row)
                        return true;
            return false;
        }

        #endregion

        #region 食物线程

        public void FoodTimer_Tick(object sender, EventArgs e)
        {
            foodTimer.Interval = snakeTimer.Interval;
            //创建食物
            if (foodEat)
            {
                Infrastructure.Core.Snake snake = new Infrastructure.Core.Snake();
                while (true)
                {
                    row = location.Next(1, 50);
                    col = location.Next(1, 60);
                    for (int i = 0; i < snakeIndex.Count; i++)
                        if (row != CollectionSnake[i].Row && col != CollectionSnake[i].Column)
                        {
                            snake.Column = col;
                            snake.Row = row;
                            CollectionSnake.Add(snake);
                            isCreate = true;
                            foodEat = false;
                            break;
                        }

                    if (isCreate)
                    {
                        isCreate = false;
                        break;
                    }
                }
            }
        }

        #endregion
    }
}